import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Select } from 'antd';
import CascaderUl from '@components/cascader-ul';
import _ from 'lodash';
import './index.less';

function flattenOption(options = [], parents = [], fieldNames = {}) {
  const {
    label: labelField = 'label',
    value: valueField = 'value',
    children: childrenField = 'children'
  } = fieldNames;
  const flattened = [];
  for (const option of options) {
    if (_.get(option, [childrenField, 'length'])) {
      flattened.push(
        ...flattenOption(option[childrenField], parents.concat(option[labelField]), fieldNames)
      );
    } else {
      flattened.push({
        label: parents.concat(option[labelField]).join('/'),
        value: option[valueField]
      });
    }
  }
  return flattened;
}
function getOptionLabels(options = [], fieldNames = {}) {
  const { label: labelField = 'label', children: childrenField = 'children' } = fieldNames;
  const labels = [];
  for (const option of options) {
    if (_.get(option, [childrenField, 'length'])) {
      labels.push(...getOptionLabels(option[childrenField], fieldNames));
    } else {
      labels.push(option[labelField]);
    }
  }
  return labels;
}

class SelectWithCascader extends Component {
  static propTypes = {
    value: PropTypes.array,
    onChange: PropTypes.func,
    options: PropTypes.array,
    fieldNames: PropTypes.object,
    placeholder: PropTypes.string,
    mode: PropTypes.string
  };
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      search: '',
      selects: []
    };
    this.containerRef = React.createRef();
  }
  triggerSelect = value => {
    const selects = this.props.value || [];
    if (selects.includes(value)) {
      this.props.onChange(selects.filter(i => i !== value));
    } else {
      this.props.onChange(selects.concat(value));
    }
  };
  onSelect = value => {
    const { value: selects = [], options, fieldNames } = this.props;
    const labels = getOptionLabels(options, fieldNames);
    if (!selects.includes(value) && !labels.includes(value)) {
      this.props.onChange(selects.concat(value));
    }
  };
  onDeselect = value => {
    const selects = this.props.value || [];
    if (selects.includes(value)) {
      this.props.onChange(selects.filter(i => i !== value));
    }
  };
  render() {
    const { search } = this.state;
    const {
      value: selects = [],
      options = [],
      fieldNames = {},
      placeholder,
      mode = 'tags'
    } = this.props;

    const selectOptions = flattenOption(options, [], fieldNames);
    return (
      <div className="select-with-cascader" ref={this.containerRef}>
        <Select
          className="select"
          mode={mode || 'tags'}
          placeholder={placeholder}
          dropdownClassName="select-with-cascader-dropdown"
          getPopupContainer={() => this.containerRef.current}
          onSearch={search => this.setState({ search })}
          onDropdownVisibleChange={visible => !visible && search && this.setState({ search: '' })}
          value={selects}
          onSelect={this.onSelect}
          onDeselect={this.onDeselect}
          dropdownRender={() => {
            return (
              <CascaderUl
                addEmptySearch={mode === 'tags'}
                onChange={this.triggerSelect}
                search={search}
                options={options}
                value={selects}
                fieldNames={{ label: 'name', value: '_id', children: 'children' }}
              />
            );
          }}
        >
          {selectOptions.map(option => (
            <Select.Option key={option.value} value={option.value}>
              {option.label}
            </Select.Option>
          ))}
        </Select>
      </div>
    );
  }
}

export default SelectWithCascader;
